package com.tianji.learning.service.impl;

import cn.hutool.db.DbRuntimeException;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author yb0os1
 * @since 2024-12-25
 */
@Service
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {
    private final InteractionQuestionMapper questionMapper;
    private final UserClient userClient;
    private final RemarkClient remarkClient;
    private final StringRedisTemplate redisTemplate;

    @Override
    public void saveReply(ReplyDTO replyDTO) {
        //1、获取当前用户
        Long userId = UserContext.getUser();
        //2、保存回答或评论
        InteractionReply reply = BeanUtils.copyBean(replyDTO, InteractionReply.class);
        reply.setUserId(userId);
        save(reply);
        //3、判断是回答还是评论 回答是对问题的第一次的回复  评论就是对回答的回复
        InteractionQuestion question = questionMapper.selectById(replyDTO.getQuestionId());
        boolean isUpdate;
        if (replyDTO.getAnswerId() == null) {
            //3、针对回答进行处理 需要修改question表 answerId、answerTimes status
            question.setLatestAnswerId(reply.getId());
            question.setAnswerTimes(question.getAnswerTimes() + 1);
            isUpdate = true;
        } else {
            //4、针对评论进行处理
            lambdaUpdate()
                    .setSql("reply_times = reply_times + 1")
                    .eq(InteractionReply::getId, replyDTO.getAnswerId())
                    .update();
            isUpdate = false;
        }
        //5、是否是学生进行提交
        if (replyDTO.getIsStudent()) {
            isUpdate = true;
            question.setStatus(QuestionStatus.UN_CHECK);
        }

        if (isUpdate) questionMapper.updateById(question);
    }

    /**
     * 分页查询回答和评论列表
     *
     * @param query
     * @return
     */

    @Override
    public PageDTO<ReplyVO> queryReplyPage(ReplyPageQuery query) {
        //1、参数校验 questionId 和 answerId 两者不可都为空
        if (query.getQuestionId() == null && query.getAnswerId() == null) {
            return PageDTO.empty(0L, 0L);
        }
        //2、基于questionId 和 answerId 分页查询查找问题的回答和评论
        Page<InteractionReply> replyPage = lambdaQuery()
                .eq(query.getQuestionId() != null, InteractionReply::getQuestionId, query.getQuestionId())
                .eq(InteractionReply::getAnswerId, query.getAnswerId() == null ? 0L : query.getAnswerId())
                .eq(InteractionReply::getHidden, false)
                .page(query.toMpPage(
                        new OrderItem("liked_times", false),
                        new OrderItem("create_time", true)
                ));
        List<InteractionReply> records = replyPage.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(replyPage);
        }
        //3、开始填补字段
        Map<Long, UserDTO> UserDTOMap = populateFields(records, false);
        //4、封装vo
        List<ReplyVO> vos = getVoList(records, UserDTOMap, false);
        return PageDTO.of(replyPage, vos);
    }

    private List<ReplyVO> getVoList(List<InteractionReply> records, Map<Long, UserDTO> UserDTOMap, boolean isAdmin) {
        List<ReplyVO> vos = new ArrayList<>();
        List<Long> bizIds = records.stream().map(InteractionReply::getId).collect(Collectors.toList());
        Set<Long> likedBizIds = remarkClient.batchQueryLikedStatus(bizIds);//当前用户点赞的bizId
        for (InteractionReply record : records) {
            ReplyVO vo = BeanUtils.toBean(record, ReplyVO.class);
            if (UserDTOMap != null) {
                if (isAdmin || !record.getAnonymity()) {
                    UserDTO userDTO = UserDTOMap.get(record.getUserId());
                    if (userDTO != null) {
                        vo.setUserName(userDTO.getName());
                        vo.setUserIcon(userDTO.getIcon());
                        vo.setUserType(userDTO.getType());
                    }
                }
                UserDTO userDTO = UserDTOMap.get(record.getTargetUserId());
                if (userDTO != null) {
                    vo.setTargetUserName(userDTO.getName());
                }
            }
            if (likedBizIds != null&& likedBizIds.contains(record.getId())){
                vo.setLiked(true);
            }
            //获取点赞的数量 缓存中存在使用缓存的  缓存中不存在使用mysql
            Long score = redisTemplate.opsForSet().size("likes:bizId:"+record.getId());
            if (score != null){
                vo.setLikedTimes(score.intValue());
            }
            vos.add(vo);
        }
        return vos;
    }

    /**
     * 管理端分页查询回答和评论列表
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<ReplyVO> queryReplyPageByAdmin(ReplyPageQuery query) {
        //1、参数校验 questionId 和 answerId 两者不可都为空
        if (query.getQuestionId() == null && query.getAnswerId() == null) {
            return PageDTO.empty(0L, 0L);
        }
        //2、基于questionId 和 answerId 分页查询查找问题的回答和评论
        Page<InteractionReply> replyPage = lambdaQuery()
                .eq(query.getQuestionId() != null, InteractionReply::getQuestionId, query.getQuestionId())
                .eq(InteractionReply::getAnswerId, query.getAnswerId() == null ? 0L : query.getAnswerId())
                .page(query.toMpPage(
                        new OrderItem("liked_times", false),
                        new OrderItem("create_time", true)
                ));
        List<InteractionReply> records = replyPage.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(replyPage);
        }
        //3、填充字段
        Map<Long, UserDTO> UserDTOMap = populateFields(records, true);
        //4、封装vo
        List<ReplyVO> vos = getVoList(records, UserDTOMap, true);
        return PageDTO.of(replyPage, vos);
    }

    @Override
    public void updateStatus(Long id, Boolean hidden) {
        InteractionReply one = lambdaQuery().eq(InteractionReply::getId, id).one();
        if (one == null) {
            throw new BizIllegalException("该回答不存在");
        }
        Set<Long> ids = new HashSet<>();
        ids.add(id);
        //需要隐藏改评论/回答下的所有的评论
        List<InteractionReply> replyList = lambdaQuery().eq(InteractionReply::getTargetReplyId, id).list();
        if (CollUtils.isNotEmpty(replyList)) {
            Set<Long> collect = replyList.stream().map(InteractionReply::getId).collect(Collectors.toSet());
            ids.addAll(collect);

            boolean success = lambdaUpdate()
                    .set(InteractionReply::getHidden, hidden)
                    .in(InteractionReply::getId, ids)
                    .update();
            if (!success) {
                throw new DbRuntimeException("更新回答状态失败");
            }
        }
    }

    private Map<Long, UserDTO> populateFields(List<InteractionReply> records, boolean isAdmin) {
        Set<Long> ids = new HashSet<>();
        Set<Long> targetReplyIds = new HashSet<>();
        for (InteractionReply record : records) {
            if (isAdmin || !record.getAnonymity()) {
                ids.add(record.getUserId());
                ids.add(record.getTargetUserId());
            }
            if (record.getTargetReplyId() != null && record.getTargetReplyId() > 0L) {
                targetReplyIds.add(record.getTargetReplyId());
            }
        }
        //查找targetReplyIds中的userId targetReplyIds是针对回复评论的评论id
        if (CollUtils.isNotEmpty(targetReplyIds)) {
            List<InteractionReply> targetReplyList = lambdaQuery()
                    .in(InteractionReply::getId, targetReplyIds)
                    .list();
            Set<Long> collect = targetReplyList.stream().
                    filter(t -> isAdmin || !t.getAnonymity()).
                    map(InteractionReply::getUserId).
                    collect(Collectors.toSet());
            ids.addAll(collect);
        }
        List<UserDTO> userDTOS = userClient.queryUserByIds(ids);
        //包含了回复者昵称 回复者头像 回复者类型 目标用户名字
        return CollUtils.isNotEmpty(userDTOS) ? userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, u -> u)) : null;
    }

}
